package com.ruoyi.bpm.controller.admin.definition;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
import com.ruoyi.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
import com.ruoyi.bpm.convert.definition.BpmProcessDefinitionConvert;
import com.ruoyi.bpm.domain.category.BpmCategory;
import com.ruoyi.bpm.domain.definition.BpmForm;
import com.ruoyi.bpm.domain.definition.BpmProcessDefinitionInfo;
import com.ruoyi.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy;
import com.ruoyi.bpm.service.category.BpmCategoryService;
import com.ruoyi.bpm.service.definition.BpmFormService;
import com.ruoyi.bpm.service.definition.BpmProcessDefinitionService;
import com.ruoyi.common.core.core.domain.R;
import com.ruoyi.common.orm.core.page.TableDataInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import static com.ruoyi.common.core.utils.CollectionUtils.convertSet;

@Tag(name = "管理后台 - 流程定义")
@RestController
@RequestMapping("/bpm/process-definition")
@Validated
public class BpmProcessDefinitionController {

    @Resource
    private BpmProcessDefinitionService processDefinitionService;
    @Resource
    private BpmFormService formService;
    @Resource
    private BpmCategoryService categoryService;

    @GetMapping("/page")
    @Operation(summary = "获得流程定义分页")
    @SaCheckPermission("bpm:process-definition:query")
    public R<TableDataInfo<BpmProcessDefinitionRespVO>> getProcessDefinitionPage(
        BpmProcessDefinitionPageReqVO pageReqVO) {
        TableDataInfo<ProcessDefinition> pageResult = processDefinitionService.getProcessDefinitionPage(pageReqVO);
        if (CollUtil.isEmpty(pageResult.getRows())) {
            return R.ok(TableDataInfo.build());
        }

        // 获得 Category Map
        Map<String, BpmCategory> categoryMap = categoryService.getCategoryMap(
            convertSet(pageResult.getRows(), ProcessDefinition::getCategory));
        // 获得 Deployment Map
        Map<String, Deployment> deploymentMap = processDefinitionService.getDeploymentMap(
            convertSet(pageResult.getRows(), ProcessDefinition::getDeploymentId));
        // 获得 BpmProcessDefinitionInfoDO Map
        Map<String, BpmProcessDefinitionInfo> processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap(
            convertSet(pageResult.getRows(), ProcessDefinition::getId));
        // 获得 Form Map
        Map<Long, BpmForm> formMap = formService.getFormMap(
            convertSet(processDefinitionMap.values(), BpmProcessDefinitionInfo::getFormId));
        return R.ok(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionPage(
            pageResult, deploymentMap, processDefinitionMap, formMap, categoryMap));
    }

    @GetMapping("/list")
    @Operation(summary = "获得流程定义列表")
    @Parameter(name = "suspensionState", description = "挂起状态", required = true, example = "1")
    // 参见 Flowable SuspensionState 枚举
    @SaCheckPermission("bpm:process-definition:query")
    public R<List<BpmProcessDefinitionRespVO>> getProcessDefinitionList(
        @RequestParam("suspensionState") Integer suspensionState) {
        List<ProcessDefinition> list = processDefinitionService.getProcessDefinitionListBySuspensionState(suspensionState);
        if (CollUtil.isEmpty(list)) {
            return R.ok(Collections.emptyList());
        }

        // 获得 BpmProcessDefinitionInfoDO Map
        Map<String, BpmProcessDefinitionInfo> processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap(
            convertSet(list, ProcessDefinition::getId));
        return R.ok(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionList(
            list, null, processDefinitionMap, null, null));
    }

    @GetMapping("/get")
    @Operation(summary = "获得流程定义")
    @Parameter(name = "id", description = "流程编号", required = true, example = "1024")
    @Parameter(name = "key", description = "流程定义标识", required = true, example = "1024")
    @SaCheckPermission("bpm:process-definition:query")
    public R<BpmProcessDefinitionRespVO> getProcessDefinition(
        @RequestParam(value = "id", required = false) String id,
        @RequestParam(value = "key", required = false) String key) {
        ProcessDefinition processDefinition = id != null ? processDefinitionService.getProcessDefinition(id)
            : processDefinitionService.getActiveProcessDefinition(key);
        if (processDefinition == null) {
            return R.ok(null);
        }
        BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId());
        List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel);
        return R.ok(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinition(
            processDefinition, null, null, null, null, bpmnModel, userTaskList));
    }

}
